select(), poll(), এবং epoll() হলো তিনটি গুরুত্বপূর্ণ সিস্টেম কল, যা নেটওয়ার্ক প্রোগ্রামিংয়ে I/O Multiplexing অর্জনের জন্য ব্যবহৃত হয়। এগুলোর মাধ্যমে একাধিক Socket বা File Descriptor-কে একসাথে পর্যবেক্ষণ করা যায় এবং এক বা একাধিক File Descriptor থেকে ইনপুট পাওয়া গেলে তা প্রক্রিয়া করা যায়। এগুলো বিশেষত নেটওয়ার্ক সার্ভার এবং উচ্চ-পারফরম্যান্স অ্যাপ্লিকেশন ডিজাইন করতে ব্যবহৃত হয়। নিচে প্রতিটি ফাংশনের ব্যবহার, প্রয়োজনীয়তা, এবং উদাহরণ দেওয়া হলো:
1. select()
select() একটি পুরনো এবং সাধারণ সিস্টেম কল, যা File Descriptor সেটগুলোকে (Sockets, Files, Pipes ইত্যাদি) পর্যবেক্ষণ করে। এটি নির্দিষ্ট File Descriptor-এ I/O অপারেশন করার জন্য প্রস্তুত কিনা তা চেক করে।
select() ফাংশনের সিগনেচার (C ভাষায়)
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
nfds: সর্বোচ্চ File Descriptor এর মান + 1।readfds: File Descriptor সেট যা Read অপারেশনের জন্য পর্যবেক্ষণ করা হবে।writefds: File Descriptor সেট যা Write অপারেশনের জন্য পর্যবেক্ষণ করা হবে।exceptfds: File Descriptor সেট যা Exceptional Condition এর জন্য পর্যবেক্ষণ করা হবে।timeout: কত সময় অপেক্ষা করবে (একটি টাইমআউট ভ্যালু)।
select() এর উদাহরণ
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/select.h>
#include <arpa/inet.h>
#define PORT 8080
int main() {
int server_fd, client_fd, max_fd, activity;
struct sockaddr_in server_addr;
fd_set read_fds;
char buffer[1024];
// Server socket তৈরি করা
server_fd = socket(AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
listen(server_fd, 3);
while (1) {
FD_ZERO(&read_fds);
FD_SET(server_fd, &read_fds);
max_fd = server_fd;
// select() কল করা
activity = select(max_fd + 1, &read_fds, NULL, NULL, NULL);
if (activity > 0 && FD_ISSET(server_fd, &read_fds)) {
client_fd = accept(server_fd, NULL, NULL);
printf("New connection accepted\n");
read(client_fd, buffer, sizeof(buffer));
printf("Received: %s\n", buffer);
close(client_fd);
}
}
close(server_fd);
return 0;
}
2. poll()
poll() হলো select()-এর একটি উন্নত সংস্করণ, যা একাধিক File Descriptor-কে পর্যবেক্ষণ করে এবং I/O অপারেশন করার জন্য প্রস্তুত কিনা তা জানায়। এটি select()-এর মতো কাজ করে, তবে এটি একটি Array ব্যবহার করে, যা select()-এর Fixed-Size Set-এর চেয়ে বেশি নমনীয়।
poll() ফাংশনের সিগনেচার (C ভাষায়)
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
fds:struct pollfdএর একটি Array যা File Descriptor এবং তাদের Event টাইপ ধারণ করে।nfds: Array-তে থাকা File Descriptor এর সংখ্যা।timeout: কতক্ষণ অপেক্ষা করবে (মিলিসেকেন্ডে)।
poll() এর উদাহরণ
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <poll.h>
#include <arpa/inet.h>
#define PORT 8080
int main() {
int server_fd, client_fd;
struct sockaddr_in server_addr;
struct pollfd fds[10];
int nfds = 1;
char buffer[1024];
// Server socket তৈরি করা
server_fd = socket(AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
listen(server_fd, 3);
fds[0].fd = server_fd;
fds[0].events = POLLIN;
while (1) {
int activity = poll(fds, nfds, -1);
if (activity > 0 && (fds[0].revents & POLLIN)) {
client_fd = accept(server_fd, NULL, NULL);
printf("New connection accepted\n");
read(client_fd, buffer, sizeof(buffer));
printf("Received: %s\n", buffer);
close(client_fd);
}
}
close(server_fd);
return 0;
}
3. epoll()
epoll() হলো Linux-এ select() এবং poll() এর আরও উন্নত সংস্করণ, যা উচ্চ-পারফরম্যান্স অ্যাপ্লিকেশন এবং সার্ভারের জন্য উপযুক্ত। এটি স্কেলেবিলিটির জন্য ডিজাইন করা হয়েছে এবং অনেক বেশি File Descriptor পরিচালনা করতে সক্ষম। epoll() ব্যবহারের মাধ্যমে বেশিরভাগ ইভেন্ট-ড্রিভেন সার্ভার এবং অ্যাপ্লিকেশন তৈরি করা হয়।
epoll() ফাংশনের তিনটি প্রধান অংশ
epoll_create():
- একটি
epollinstance তৈরি করে।
int epoll_create(int size);epoll_ctl():
- File Descriptor গুলোকে
epollinstance-এ যোগ, সরানো বা পরিবর্তন করতে ব্যবহৃত হয়।
int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);epoll_wait():
epollinstance-এর মধ্যে থাকা File Descriptor গুলোতে ইভেন্ট আছে কিনা তা চেক করে এবং এটি ইভেন্ট পাওয়া গেলে তাদের ফেরত দেয়।
int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout);epoll() এর উদাহরণ
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/epoll.h>
#include <arpa/inet.h>
#define PORT 8080
#define MAX_EVENTS 10
int main() {
int server_fd, client_fd, epoll_fd;
struct sockaddr_in server_addr;
struct epoll_event ev, events[MAX_EVENTS];
char buffer[1024];
// Server socket তৈরি করা
server_fd = socket(AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = INADDR_ANY;
server_addr.sin_port = htons(PORT);
bind(server_fd, (struct sockaddr*)&server_addr, sizeof(server_addr));
listen(server_fd, 3);
// epoll instance তৈরি করা
epoll_fd = epoll_create(1);
ev.events = EPOLLIN;
ev.data.fd = server_fd;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &ev);
while (1) {
int num_events = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);
for (int i = 0; i < num_events; i++) {
if (events[i].data.fd == server_fd) {
client_fd = accept(server_fd, NULL, NULL);
printf("New connection accepted\n");
ev.events = EPOLLIN;
ev.data.fd = client_fd;
epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &ev);
} else {
int client_fd = events[i].data.fd;
read(client_fd, buffer, sizeof(buffer));
printf("Received: %s\n", buffer);
close(client_fd);
epoll_ctl(epoll_fd, EPOLL_CTL_DEL, client_fd, NULL);
}
}
}
close(server_fd);
close(epoll_fd);
return 0;
}
তুলনা: select(), poll(), এবং epoll()
| বৈশিষ্ট্য | select() | poll() | epoll() |
|---|---|---|---|
| স্কেলেবিলিটি | সীমিত (1024 FD-এর বেশি পরিচালনা করতে পারে না) | উন্নত, কিন্তু select() এর মতো সমস্যা আছে | উচ্চ স্কেলেবিলিটি, অনেক বেশি FD পরিচালনা করতে পারে |
| কর্মক্ষমতা | ধীর, কারণ এটি প্রতিটি কলের সময় সবকিছু স্ক্যান করে | তুলনামূলকভাবে ধীর | দ্রুত, কারণ এটি শুধুমাত্র Active FD-এর উপর কাজ করে |
| ব্যবহারিকতা | ছোট অ্যাপ্লিকেশনের জন্য উপযুক্ত | মধ্যম স্কেল অ্যাপ্লিকেশনের জন্য | উচ্চ-পারফরম্যান্স এবং বড় অ্যাপ্লিকেশন এবং সার্ভারের জন্য |
| পোর্টেবিলিটি | POSIX মান সম্মত, অনেক সিস্টেমে সমর্থিত | POSIX মান সম্মত, অনেক সিস্টেমে সমর্থিত | Linux নির্দিষ্ট |
Read more